﻿using System.Net.Sockets;
using System.Net;
using System.Threading;
using System;

namespace AE.Remoting {
    /// <summary>
    /// Logic for the host service.
    /// </summary>
    public class Service : IDisposable {

        private bool p_IsDisposed;
        private TcpListener p_Listener;
        private Thread p_AcceptClientThread;
        private bool p_Stopping;
        private ServiceQueue<TcpClient> p_Pool;

        public Service() {
            Start();
        }

        public void Dispose() {
            p_IsDisposed = true;
            Stop();
        }

        public event ThreadExceptionEventHandler Exception;

        public void OnException(Exception ex) {
            if (Exception != null) {
                Exception(this, new ThreadExceptionEventArgs(ex));
            }
        }

        public void Start() {
            p_Stopping = false;
            p_Listener = new TcpListener(IPAddress.Any, Settings.Current.RemotingPort);

            p_Listener.ExclusiveAddressUse = true;
            p_Listener.Start();
            p_AcceptClientThread = new System.Threading.Thread(AcceptClient);
            p_AcceptClientThread.Start();

            p_Pool = new ServiceQueue<TcpClient>(Utilities.RemoteTcpServer, 20, "AppService", ThreadPriority.Normal);
            p_Pool.OnException += OnException;
        }

        private void AcceptClient(object state) {
            try {
                do {
                    if (p_Stopping) return;
                    TcpClient tcp = p_Listener.AcceptTcpClient();
                    p_Pool.Enqueue(tcp);
                }
                while (true);
            } catch (Exception ex) {
                OnException(ex);
            }
        }

        public bool IsDisposed {
            get { return p_IsDisposed; }
        }

        public void Stop() {
            p_Stopping = true;
            p_Pool.Dispose();

            if (p_AcceptClientThread != null) p_AcceptClientThread.Abort();
            if (p_Listener != null) p_Listener.Stop();

            p_AcceptClientThread = null;
            p_Listener = null;
        } 
    }
} 